package org.ccay.core.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.ccay.core.ioc.Ccay;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.log.ILogConvert;
import org.ccay.core.log.ILogger;
import org.ccay.core.log.CcayLogJsonConvert;
import org.ccay.core.log.CcayLogJsonProperty;
import org.ccay.core.log.JsonSerializableProperties;
import org.ccay.core.log.LogConvertContext;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
import org.codehaus.jackson.map.util.ClassUtil;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.NumericNode;
import org.codehaus.jackson.node.ObjectNode;
import org.springframework.beans.BeanUtils;

public class JsonGenerator {
	/**
	 * 记录日志.
	 */
	private final static ILogger log = CcayLoggerFactory.getLogger(JsonGenerator.class);
	/**
	 * 分析对象属性，标志需要序列化的属性传给createJsonNode（）处理，创建 jackson的JsonNode对象.
	 * @param value
	 *            待解析的对象.
	 * @param node
	 *            待赋属性值的jackson节点对象
	 */
	private static void resolveFields(Object value,ObjectNode node,int deep,int currentDeep){
			// JsonSerializableProperties标识类需要序列化的Fields.
			JsonSerializableProperties annotclz = value.getClass().getAnnotation(JsonSerializableProperties.class);
			if(annotclz == null || CollectionUtil.isNullOrEmpty(annotclz.value()) || currentDeep >= deep){
				// 如果类未定义需要序列化的属性列表，直接返回.
				return ;
			}
			Class clz = value.getClass();
			JsonGenerator.SerializableClass serializableClass = new JsonGenerator.SerializableClass(clz);
			// 需要序列化的属性列表.
			Set<String> serFieldNames = serializableClass.findSerFieldNames();
			Set<String> orderFieldNames = serializableClass.findOrderFieldNames();
			Map<String,String> fieldAliasMapper = serializableClass.findFieldNameAlias();
			Map<String,ILogConvert> fieldConvetMap =serializableClass.getFieldConverts();
			//排序后需要序列化的属性名集合
			Set<String> orderedSerFieldNames = serFieldNames;
			if(!orderFieldNames.isEmpty()){
				orderedSerFieldNames = orderedSerFileds(serFieldNames,orderFieldNames);
			}
			try {
				for (String fieldName : orderedSerFieldNames) {
					PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(clz, fieldName);
					if(null != pd){
						// 未设置属性序列化别名，将使用字段名作为序列化的名字.
						String serPropertyAlias = StringUtil.isNullOrEmpty(fieldAliasMapper.get(fieldName))?fieldName:fieldAliasMapper.get(fieldName);
						// 读取方法的返回值.
						Object fieldValue =  pd.getReadMethod().invoke(value, new Object[]{});
						int nextDeep = currentDeep+1;
						
//						Field field = clz.getDeclaredField(fieldName) ;
//						CcayLogJsonConvert convertAnno = field.getAnnotation(CcayLogJsonConvert.class);
						//有自定义转换器
						ILogConvert logConvert = fieldConvetMap.get(fieldName);
						if(logConvert !=  null){							
							node.put(serPropertyAlias, logConvert.convert(new LogConvertContext(fieldName, fieldValue, value)));
						}else{
							node.put(serPropertyAlias, createJsonNode(fieldValue,deep,nextDeep));
						}
						
					}
				}
			} catch (Exception e) {
				// 抛出异常，继续执行后续代码.
				log.error(e);
			}
	}
	/**
	 * 按照用户定义的属性序列化顺序列表排序待序列化的属性.
	 * @param serFieldNames
	 *            配置的必须序列化的属性列表.
	 * @param orderFieldNames
	 *            自定义的属性序列化顺序列表.
	 * @return Set<String> 按用户自定义顺序排序后的序列化属性列表.
	 */
	private static Set<String> orderedSerFileds(Set<String> serFieldNames,Set<String> orderFieldNames){
		// 差集数据.
		// 属性序列化顺序列表.
		Set<String> orderedFieldNameSet = new LinkedHashSet<String>();
		orderedFieldNameSet.addAll(orderFieldNames);
		String arraytoString = Arrays.toString(serFieldNames.toArray());
		// 删除掉orderFieldNameSet中没有在需要序列化的属性列表中的元素.
		for (String orderFieldName : orderFieldNames) {
			int subIndexOf = arraytoString.indexOf(orderFieldName);
			if(subIndexOf<0){
				orderedFieldNameSet.remove(orderFieldName);
			}
		}
		orderedFieldNameSet.addAll(serFieldNames);
		return orderedFieldNameSet;
	}

	/**
	 * 
	 * 工具方法，判断是否指定注解JsonSerializableProperties
	 * @param annotclz
	 * @return
	 */
	private static boolean isNullorValueEmpty(JsonSerializableProperties annotclz){
		
		if(annotclz !=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
			return false;
		}
		return true;
	}
	
	 private static class SerializableClass{
		 public SerializableClass(Class clz){
			 this.clz = clz;
		 }
		 Class clz;
		 public Class getClz() {
			return clz;
		}
		public void setClz(Class clz) {
			this.clz = clz;
		}
		/**
		 * 
		 * @return
		 */
		public Set<String> findSerFieldNames(){
			Set<String> serFieldNames = new LinkedHashSet<String>();
			JsonSerializableProperties annotclz = (JsonSerializableProperties)clz.getAnnotation(JsonSerializableProperties.class);
			if(annotclz!=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
				serFieldNames.addAll(Arrays.asList(annotclz.value()));
			}
			serFieldNames.addAll(findSupSerFieldNames());
			return serFieldNames;
		}
		/**
		 * 
		 * @return
		 */
		private Set<String> findSupSerFieldNames()
		{
			Set<String> superSserFieldNames = new LinkedHashSet<String>();
			JsonSerializableProperties annotclz = (JsonSerializableProperties)clz.getAnnotation(JsonSerializableProperties.class);
			if(annotclz!=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
				//获取cls 对象所表示的类或接口的所有超类 
				 List<Class<?>> superClzs = ClassUtil.findSuperTypes(clz, null);
				// 如果类未定义需要序列化的属性列表，直接返回.
				for (Class<?> superClz : superClzs) {
					JsonSerializableProperties supAnnotclz = superClz.getAnnotation(JsonSerializableProperties.class);
					if(!isNullorValueEmpty(supAnnotclz)){
						String[] serFieldNames = supAnnotclz.value();
						superSserFieldNames.addAll(Arrays.asList(serFieldNames));
					}
				}		
			}
			return superSserFieldNames;
		}
		/**
		 * 
		 * @return
		 */
		public Set<String> findOrderFieldNames(){
			Set<String> orderFieldNames = new LinkedHashSet<String>();
			JsonPropertyOrder annotclz = (JsonPropertyOrder)clz.getAnnotation(JsonPropertyOrder.class);
			if(annotclz!=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
				orderFieldNames.addAll(Arrays.asList(annotclz.value()));
			}
			orderFieldNames.addAll(findSuperOrderFieldNams());
			return orderFieldNames;
		}
		/**
		 * 
		 * @return
		 */
		private Set<String> findSuperOrderFieldNams(){
			Set<String> superOrderFieldNames = new LinkedHashSet<String>();
			JsonSerializableProperties annotclz = (JsonSerializableProperties)clz.getAnnotation(JsonSerializableProperties.class);
			if(annotclz!=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
				//获取cls 对象所表示的类或接口的所有超类 
				 List<Class<?>> superClzs = ClassUtil.findSuperTypes(clz, null);
				// 如果类未定义需要序列化的属性列表，直接返回.
				for (Class<?> superClz : superClzs) {
					JsonPropertyOrder supAnnotclz = superClz.getAnnotation(JsonPropertyOrder.class);
					if(supAnnotclz!=null && (supAnnotclz.value()!=null)){
						String[] orderFieldNames = annotclz.value();
						superOrderFieldNames.addAll(Arrays.asList(orderFieldNames));
					}
				}		
			}
			return superOrderFieldNames;
		}
		/**
		 */
		public Map<String,String> findFieldNameAlias(){
			Map<String,String> fieldAliasMapper = new HashMap<String,String>();
			Field[] field = clz.getDeclaredFields();
			for (Field fld : field) {
				CcayLogJsonProperty propertyAnnotate = fld.getAnnotation(CcayLogJsonProperty.class);
				if(propertyAnnotate!=null && !fieldAliasMapper.containsKey(fld.getName())){
					fieldAliasMapper.put(fld.getName(), propertyAnnotate.value());
				}
			}
			fieldAliasMapper.putAll(findSuperFieldNameAlias());
			return fieldAliasMapper;
		}
		/**
		 * 
		 * 获取所有父亲或实现接口配置的属性别名信息.
		 * @return
		 */
		private Map<String,String> findSuperFieldNameAlias(){
			Map<String,String> fieldAliasMapper = new HashMap<String,String>();
			JsonSerializableProperties annotclz = (JsonSerializableProperties)clz.getAnnotation(JsonSerializableProperties.class);
			if(annotclz!=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
				//获取cls 对象所表示的类或接口的所有超类 
				 List<Class<?>> superClzs = ClassUtil.findSuperTypes(clz, null);
				// 如果类未定义需要序列化的属性列表，直接返回.
				for (Class<?> superClz : superClzs) {
					Field[] field = superClz.getDeclaredFields();
					fieldAliasMapper.putAll(getFieldAliasMapper(field));
				}		
			}
			return fieldAliasMapper;
		}
		/**
		 * 获得日志的转换器
		 * @return
		 */
		 private     Map<String,ILogConvert> getFieldConverts(){
			 Map<String,ILogConvert> fieldConvertMap = new HashMap<String,ILogConvert>();
				JsonSerializableProperties annotclz = (JsonSerializableProperties)clz.getAnnotation(JsonSerializableProperties.class);
				if(annotclz!=null && !CollectionUtil.isNullOrEmpty(annotclz.value())){
					//获取cls 对象所表示的类或接口的所有超类 
					 List<Class<?>> superClzs = ClassUtil.findSuperTypes(clz, null);
					 superClzs.add(clz);
					// 如果类未定义需要序列化的属性列表，直接返回.
					for (Class<?> superClz : superClzs) {
						Field[] field = superClz.getDeclaredFields();
						for(Field f :field){
							if(f.isAnnotationPresent(CcayLogJsonConvert.class)){
								CcayLogJsonConvert convert=f.getAnnotation(CcayLogJsonConvert.class);
								ILogConvert logConvert = Ccay.getContext().getBean(convert.value(),ILogConvert.class);
								fieldConvertMap.put(f.getName(), logConvert);
							}
						}						
					}		
				}
			 
			 return fieldConvertMap;
		 }
	 }
	
	 /**
	  * 把for (Class<?> superClz : superClzs) {循环中的方法抽出独立的方法  降低复杂度
	  * @param fieldAliasMapper
	  * @param field
	  */
	 private static Map<String,String> getFieldAliasMapper(Field[] field){
		 Map<String,String> fieldAliasMapper = new HashMap<String,String>();
		 for (Field fld : field) {
			 CcayLogJsonProperty propertyAnnotate = fld.getAnnotation(CcayLogJsonProperty.class);
				if(propertyAnnotate!=null && !fieldAliasMapper.containsKey(fld.getName())){
					fieldAliasMapper.put(fld.getName(), propertyAnnotate.value());
				}
			}
		 return fieldAliasMapper;
	 }
	/**
	 * 根据传入的Object具体类型创建jackson的JsonNode子类型.
	 * 
	 * 
	 * @param value
	 * @return
	 */
	public static JsonNode createJsonNode(Object value,final int deep,int currentDeep){
		JsonNode node = JsonNodeFactory.instance.nullNode();
		if(deep < currentDeep){
			return node;
		}
		if(value == null){
			node = JsonNodeFactory.instance.nullNode();
			return node;
		}
		Class clz = value.getClass();
		if(String.class ==clz){
			node = JsonNodeFactory.instance.textNode((String)value);
			return node;
			
		}
		if(clz.isPrimitive() || (value  instanceof Number)){
			node = numericNodeGenerator(clz,value);
			return node;
		}
		
		if(java.util.Date.class == clz){
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			node = JsonNodeFactory.instance.textNode(sdf.format(((Date)value)));
			return node;
		}
		if(Collection.class.isAssignableFrom(clz)){
			// 处理集合类型.
			Collection cols = (Collection)value;
			if(cols.isEmpty()){
				return JsonNodeFactory.instance.textNode(" ");
			}
			ArrayNode containerNode = JsonNodeFactory.instance.arrayNode();
			for (Object item : cols) {
				containerNode.add(createJsonNode(item,deep,currentDeep));
			}
			node = containerNode;
			return node;
		}
		if(Map.class.isAssignableFrom(clz)){
			Map m = (Map)value;
			if(m.isEmpty()){
				return JsonNodeFactory.instance.textNode(" ");
			}
			ObjectNode mNode = JsonNodeFactory.instance.objectNode();
			for (Iterator iter = m.entrySet().iterator(); iter.hasNext();) {
				Map.Entry paraEntry = (Entry) iter.next();
				Object nextValue = paraEntry.getKey();
				String key = nextValue == null?"null":nextValue.toString();
				mNode.put(key,createJsonNode(m.get(nextValue),deep,currentDeep));
			}
			node = mNode;
			return node;
		}
		if(clz.isArray()){
			// Array类型.
			Object[] os = (Object[])value;
			
			if(CollectionUtil.isNullOrEmpty(os )){
				return JsonNodeFactory.instance.textNode(" ");
			}
			ArrayNode containerNode = JsonNodeFactory.instance.arrayNode();
			for(int i=0;i<os.length;i++){
				containerNode.add(createJsonNode(os[i],deep,currentDeep));
			}
			node = containerNode;
			return node;
		}
		
		if(clz.isEnum()){
			// Enum类型处理.
			node = JsonNodeFactory.instance.textNode((((Enum)value).name()));
			return node;
		}else{
			// 其他类型.
			ObjectNode objNode = (ObjectNode)JsonNodeFactory.instance.objectNode();
			//当递归的深度大于指定的深度时，不再递归，避免出现内存泄露.
			resolveFields(value,objNode,deep,currentDeep);
			node = objNode;
			return node;
		}
	}
	/**
	 * 根据原始类型中数值类型或其包装类型生成jackson中的NumericNode类型节点.
	 * 
	 * @param propertyClz
	 *            数值类型的Class（原始类型Class/原始类型的包装类型Class.）
	 * @param value
	 *            数值类型值
	 * @return jackson中的NumericNode类型节点.
	 */
	private static NumericNode numericNodeGenerator(Class propertyClz,Object value){
		if(wrapperType(propertyClz) == Integer.class){
			Integer propertyValue = (Integer)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		} 
		if(wrapperType(propertyClz) == Long.class ){
			Long propertyValue = (Long)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		} 
		if(wrapperType(propertyClz) == Double.class ){
			Double propertyValue = (Double)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		} 
		if(wrapperType(propertyClz) == Float.class ){
			Float propertyValue = (Float)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		} 
		if(wrapperType(propertyClz) == Byte.class ){
			Byte propertyValue = (Byte)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		} 
		if(wrapperType(propertyClz) == Short.class){
			Short propertyValue = (Short)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		} 
		if(wrapperType(propertyClz) == Character.class){
			Character propertyValue = (Character)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		}
		if(wrapperType(propertyClz) == BigDecimal.class){
			BigDecimal propertyValue = (BigDecimal)value;
			return JsonNodeFactory.instance.numberNode(propertyValue);
		}else{
			throw new IllegalArgumentException("Class "+propertyClz.getName()+" is not a primitive type");
		}
	}
	/**
	 * 根据原始类型Class返回其包装类型的Class.
	 * 
	 * 
	 * @param primitiveType
	 *            原始类型Type
	 * @return Class<?>包装类型的Class
	 */
	private static Class<?> wrapperType(Class<?> primitiveType){
		if (primitiveType == Integer.class || primitiveType == Integer.TYPE) {
	        return Integer.class;
	    }
	    if (primitiveType == Long.class || primitiveType == Long.TYPE) {
	        return Long.class;
	    }
	    if (primitiveType == Boolean.class || primitiveType == Boolean.TYPE) {
	        return Boolean.class;
	    }
	    if (primitiveType == Double.class || primitiveType == Double.TYPE) {
	        return Double.class;
	    }
	    if (primitiveType == Float.class || primitiveType == Float.TYPE) {
	        return Float.class;
	    }
	    if (primitiveType == Byte.class || primitiveType == Byte.TYPE) {
	        return Byte.class;
	    }
	    if (primitiveType == Short.class || primitiveType == Short.TYPE) {
	        return Short.class;
	    }
	    if (primitiveType == Character.class || primitiveType == Character.TYPE) {
	        return Character.class;
	    }
	    if (primitiveType == BigDecimal.class) {
	        return BigDecimal.class;
	    }
	    return null;
	}
	/**
	 * 按照用户定义的属性序列化顺序列表排序待序列化的属性.
	 * 
	 * 
	 * @param serFieldNames
	 *            配置的必须序列化的属性列表.
	 * @param orderFieldNames
	 *            自定义的属性序列化顺序列表.
	 * @return Set<String> 按用户自定义顺序排序后的序列化属性列表.
	 */
	/**private static Set<String> orderedSerFileds(String[] serFieldNames,String[] orderFieldNames){
		// 差集数据.
		// 属性序列化顺序列表.
		Set<String> orderedFieldNameSet = new LinkedHashSet<String>();
		Collections.addAll(orderedFieldNameSet, orderFieldNames);
		
		String arraytoString = Arrays.toString(serFieldNames);
		// 删除掉orderFieldNameSet中没有在需要序列化的属性列表中的元素.
		for(int _index = 0;_index<orderFieldNames.length;_index++){
			int subIndexOf = arraytoString.indexOf(orderFieldNames[_index]);
			if(subIndexOf<0){
				orderedFieldNameSet.remove(orderFieldNames[_index]);
			}
		}
		Collections.addAll(orderedFieldNameSet, serFieldNames);
		return orderedFieldNameSet;
	}**/
}
